function typeClass(obj) { 
   var funcNameRegex = /function (.{1,})\(/;
   var results = (funcNameRegex).exec((obj).constructor.toString());
   return (results && results.length > 1) ? results[1] : "";
};

String.prototype.toRGB = function(alpha){
	return (new Color(this)).toRGB(alpha);
};
String.prototype.toDark = function(alpha){
	return (new Color(this)).toDark(alpha);
};

(function(){
	var isFn = function(fn) { return (typeof fn == "function"); };
	Base = function(){};
	Base.extend = function(proto) {
		var k = function(magic) { // call init only if there's no magic cookie
	      if (magic != isFn && isFn(this.init)) this.init.apply(this, arguments);
	    };
	    k.prototype = new this(isFn); // use our private method as magic cookie
	    for (key in proto) (function(fn, sfn){ // create a closure
	      k.prototype[key] = !isFn(fn) || !isFn(sfn) ? fn : // add _super method
	        function() { this._super = sfn; return fn.apply(this, arguments); };
	    })(proto[key], k.prototype[key]);
	    k.prototype.constructor = k;
	    k.extend = this.extend;
	    return k;
	};
})();
Base.prototype={
	merge: function(src, dest){
		for (var prop in src ) {
			dest[prop] = src[prop];
		}
	}
};

var Color = function(s){
	this.s = s;
	this.parseRGB();
};

Color.DEFS = [ 
	{//['#00ff00', '336699']
		re: /^(\w{2})(\w{2})(\w{2})$/,
		process: function (bits){
			return [
	            parseInt(bits[1], 16),
	            parseInt(bits[2], 16),
	            parseInt(bits[3], 16)
	        ];
		}
	}, {//['rgb(123, 234, 45)', 'rgb(255,234,245)']
	    re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
	    process: function (bits){
	        return [
	            parseInt(bits[1]),
	            parseInt(bits[2]),
	            parseInt(bits[3])
	        ];
	    }
	}, { //['#fb0', 'f0f']
		re: /^(\w{1})(\w{1})(\w{1})$/,
		process: function (bits){
	        return [
	            parseInt(bits[1] + bits[1], 16),
	            parseInt(bits[2] + bits[2], 16),
	            parseInt(bits[3] + bits[3], 16)
	        ];
	    }
	}, {//['rgb(123, 234, 45)', 'rgb(255,234,245)']
	    re: /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(.*)\)$/,
	    process: function (bits){
	        return [
	            parseInt(bits[1]),
	            parseInt(bits[2]),
	            parseInt(bits[3]),
	            parseFloat(bits[4])
	        ];
	    }
	}
];

Color.prototype= {
	constructor: Color,
	parseRGB: function(){
		var s = this.s;
		if (s.charAt(0) == '#'){
	        s = s.substr(1,6);
	    }
	    s = s.replace(/ /g,'');
	    s = s.toLowerCase();
	    for (var i = 0; i < Color.DEFS.length; i++) {
	        var bits = Color.DEFS[i].re.exec(s);
	        if (bits) {
	            channels = Color.DEFS[i].process(bits);
	            this.r = channels[0];
	            this.g = channels[1];
	            this.b = channels[2];
	            if(channels.length>3){
	            	this.a = channels[3];
	            }
	            this.ok = true;
	        }
	    }
	    // validate/cleanup values
	    this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
	    this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
	    this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
	    this.a = (this.a < 0 || isNaN(this.a)) ? 0 : ((this.a > 1)?1:this.a);
	}, toRGB: function (a) {
		var alpha = a;
		if(alpha!=undefined && this.a!=undefined && typeClass(alpha) == "String"){
			alpha = this.a+parseFloat(alpha);
		}
		if(alpha){
			return 'rgba(' + this.r + ', ' + this.g + ', ' + this.b + ', ' + alpha + ')';
		}else{
			return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
		}
    }, toDark: function(a){
    	var alpha = a;
		if(alpha!=undefined && this.a!=undefined && typeClass(alpha) == "String"){
			alpha = this.a+parseFloat(alpha);
		}
		if(alpha){
			return 'rgba(' + ((this.r & 0xfe)>>1) + ', ' + ((this.g & 0xfe)>>1) + ', ' + ((this.b & 0xfe)>>1) + ', ' + alpha + ')';
		}else{
			return 'rgb(' + ((this.r & 0xfe)>>1) + ', ' + ((this.g & 0xfe)>>1) + ', ' + ((this.b & 0xfe)>>1) + ')';
		}
    }
};
var CanvasChartContext = function(canvas){
	if(!canvas || !canvas.tagName || !canvas.tagName.toLowerCase()=="canvas"){
		return null;
	}
	this._canvas = canvas;
	return this;
};

CanvasChartContext.prototype = {
		constructor: CanvasChartContext,
		registerEvent: function(eName, callback){
			this._canvas[eName] = callback;
		},
		setField: function(fName, value){
			this._canvas[fName] = value;
		},
		getField: function(fName){
			return this._canvas[fName];
		}, getStage: function(){return this._canvas;},
		get2dContext: function(){ return this._canvas.getContext("2d");}
};

CanvasChartContext.create = function(id, width, height){
	var canvas = null;
	if(id.tagName && id.tagName.toLowerCase()=="canvas"){
		canvas = id;
	}else{
		var ele = document.getElementById(id);
		if(ele && ele.tagName.toLowerCase()=="canvas"){
			canvas = ele;
		}else{
			for(var i=0;i<ele.childNodes.length;i++){
				if(ele.childNodes[i].tagName.toLowerCase()=="canvas"){
					canvas = ele.childNodes[i];
					break;
				}
			}
			if(canvas==null){
				var d = document.createElement("canvas");
				d.width = width;
				d.height = height;
				ele?ele.appendChild(d):document.body.appendChild(d);
				canvas = d;
			}
		}
	}
	canvas.width = width;
	canvas.height = height;
	return canvas?new CanvasChartContext(canvas):null;
};


var CanvasChart = function(id, d, width, height){
	if(!width){ width = 450; }
	if(!height){ height = 300; }
	this.context = CanvasChartContext.create(id, width, height) ;
	if(this.context){
		this.children = new Array();
		this._init();
		this._data = this._parse(d);
		this.build();
		this.paint();
		return this;
	}
	return null;
};

CanvasChart.prototype={
	constructor:CanvasChart, version: "0.1",
	_parse: function(data){
		if(typeClass(data) == "String"){
			return new Object();
		}else{
			return data;
		}
	},_init: function(){
		this.context.setField("_instance", this);
		this.context.registerEvent("onmouseover",function(e){this._instance.mouseover(e);});
		this.context.registerEvent("onmouseout", function(e){this._instance.mouseout(e);});
		this.context.registerEvent("onmousemove", function(e){this._instance.mousemove(e);});
		this.width = this.context.getStage().width; this.height = this.context.getStage().height;
		this.context.getStage()._clearBg = function(ctx,x,y,w,h){
			//this is canvas.
			this._instance._clearBg(ctx,x,y,w,h);
		};
	},_clearBg:function(ctx,x,y,w,h){
		if(!this._data.bg_color){
			this._data.bg_color = "#f8f8d8";// <-- default to Ivory
		}
		ctx.fillStyle = this._data.bg_color;
		ctx.fillRect(x, y, w, h);
	},_drawBG: function(ctx){
		ctx.save();
		if(this._data.bg_image){
			var img = document.createElement("img");
			img.src = this._data.bg_image;
			ctx.drawImage(img, 0, 0);
		}else {
			this._clearBg(ctx,0, 0, this.width, this.height);
		}
		ctx.restore();
	},_drawText:function(ctx, base, mWidth, mHeight){
		this._drawText(ctx, base, mWidth, mHeight, null, null);
	},_drawText:function(ctx, base, mWidth, mHeight, x, y){
		ctx.save();
		//Setting the text draw style
		var text = base.text;
		var style = base.style?base.style:new Object();
		
		ctx.font = style.font?style.font:"10px 'arial'";
		ctx.strokeStyle = style.font_color?style.font_color:"#000000";
		if(style.orientation != "vertical"){
			ctx.textAlign = "left";//;style['text-align']?style['text-align']:"center";
			if(!x){
				x = 0;
				//Calculating the width of the text to be drawn
				var w = ctx.measureText(text).width;
				//Calculating the point 'x', based on the alignment
				switch(style['text-align']){
					case 'left':
						x = style['margin-left']?style['margin-left']:10;
						break;
					case 'right':
						x = mWidth - (w + style['margin-right']?style['margin-right']:0 );
						break;
							
					case 'center':
					default:
						x = (mWidth/2) - w/2;
						break;
				}
			}
			if(!y){y = style['margin-top']?style['margin-top']:10;}
		}else{
			if(!x){x = style['margin-left']?style['margin-left']:10;}
			if(!y){
				y = 0;
				//Calculating the width of the text to be drawn
				var w = ctx.measureText(text).width;
				//Calculating the point 'y', based on the alignment
				switch(style['text-align']){
					case 'bottom':
						ctx.textAlign = "left";
						y = style['margin-bottom']?style['margin-bottom']:10;
						break;
					case 'top':
						ctx.textAlign = "right";
						y = mHeight - (w + style['margin-top']?style['margin-top']:10 );
						break;
					case 'middle':
					default:
						ctx.textAlign = "center";
						y = (mHeight/2);// - (w/2);
						break;
				}
			}
			ctx.translate(x, y);
			ctx.rotate(-Math.PI/2);
			x = 0; y = 0;
		}
		//ctx.scale(0.9, 0.8);
		ctx.fillText(text, x, y);
		ctx.restore();
	},_drawTitle: function(ctx){
		var title = this._data.title;
		if(!title || !title.text){
			this._data.title.height = 0;
			return;
		}
		ctx.save();
		this._drawText(ctx, title, this.width, this.height, null, 15);
		ctx.restore();
	}, build: function(){
		var config = {
				margin_left: 5, margin_right: 5, margin_bottom: 5, margin_top: 5,
				x_axis_space: 15, y_axis_space: 15,
				x_legend_height: 15, y_legend_height: 15,
				parent: this
			};
		this._data.title.height = 20;
		var elements = this._data.elements;
		if(elements && elements.length>0){
			var chart = null;
			if("pie" == this._data.type){
				chart = new PieChart(0, this._data.title.height + config.margin_top, 
						this.width- (config.margin_left+config.margin_right), 
						this.height - (config.margin_bottom +this._data.title.height+ config.margin_top), 
						this._data, config);
			}else {
				if(this._data.x_legend==undefined){ config.x_legend_height=0; }
				if(this._data.y_legend==undefined){ config.y_legend_height=0; }
				if("bar" == this._data.type || "bar_stack" == this._data.type){
					chart = new BarChart(config.margin_left, this._data.title.height + config.margin_top, 
						this.width - (config.margin_left+config.margin_right),
						this.height - (config.margin_bottom+this._data.title.height+ config.margin_top), 
							this._data, config);
				}else if("line" == this._data.type){
					chart = new LineChart(config.margin_left, this._data.title.height + config.margin_top, 
							this.width - (config.margin_left+config.margin_right),
							this.height - (config.margin_bottom+this._data.title.height+ config.margin_top), 
								this._data, config);
				}
			}
			this.children.push(chart);
		}
		
	}, mouseover: function(e){
		this.handleMouseEvent("over", e);
	}, mouseout: function(e){
		this.handleMouseEvent("out", e);
	}, mousemove: function(e){
		this.handleMouseEvent("move", e);
	}, handleMouseEvent: function(type, e){
		var x = e.offsetX;
		var y = e.offsetY;
		//Firefox: offsetX and offsetY is not supported
		if(x==undefined || y==undefined){
			x = e.pageX - this.context.getStage().offsetLeft;
			y = e.pageY - this.context.getStage().offsetTop;
		}
		for(var i=0;i<this.children.length;i++){
			if( (this.children[i].x <= x) 
					&& ( (this.children[i].x + this.children[i].width) >= x )
					&& (this.children[i].y <= y) 
					&& ( (this.children[i].y + this.children[i].height) >= y )
				){
				this.children[i].mouseevent(type, x, y, e, this.context.get2dContext());
				break;
			}
		}
	}, paint: function(){
		var ctx = this.context.get2dContext();
		ctx.clearRect(0, 0, this.width, this.height);
		this._drawBG(ctx);
		for(var i=0;i<this.children.length;i++){
			ctx.save();
			this.children[i].paint({context: ctx});
			ctx.restore();
		}
		this._drawTitle(ctx);
	}
};

var Drawable = Base.extend({
	 init: function(x, y, width, height, data, config){
		//this._super();
		this.items = new Array();
		this.x = x; this.y = y; this.width = width; this.height = height;
		this.data = data; this.config = config;
		this.selected = false;
		this.build();
		return this;
	}, paint: function(config){
		var ctx = config.context;
		if(this.x != undefined && this.y != undefined && this.width != undefined && this.height!= undefined ){
			//ctx.clearRect(this.x, this.y, this.width, this.height);
			ctx.canvas._clearBg(ctx, this.x, this.y, this.width, this.height);
		}
		for(var i=0;i<this.items.length;i++){
			ctx.save();
			this.items[i].paint(config);
			ctx.restore();
		}
	}, mouseevent: function(type, x, y, e){
		
	}, addItem: function(itm){
		itm.parent = this;
		this.items.push(itm);
	}, noOfItems: function(){
		return this.items.length;
	}, getItem: function(i){
		return this.items[i];
	},_roundedRect:function(ctx,x,y,width,height,radius, borderColor, fillColor){
		ctx.save();
		ctx.lineStyle=borderColor;
		ctx.fillStyle=fillColor;
		ctx.beginPath();
		ctx.moveTo(x,y+radius);
		ctx.lineTo(x,y+height-radius);
		ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
		ctx.lineTo(x+width-radius,y+height);
		ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
		ctx.lineTo(x+width,y+radius);
		ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
		ctx.lineTo(x+radius,y);
		ctx.quadraticCurveTo(x,y,x,y+radius);
		ctx.fillRect(x+1,y+1,width-1,height-1);
		ctx.stroke();
		ctx.restore();
	}, build: function(){
	},_drawText:function(ctx, base, mWidth, mHeight){
		this._drawText(ctx, base, mWidth, mHeight, null, null);
	},_drawText:function(ctx, base, mWidth, mHeight, x, y){
		ctx.save();
		//Setting the text draw style
		var text = base.text;
		var style = base.style?base.style:new Object();
		
		ctx.font = style.font?style.font:"10px 'arial'";
		ctx.fillStyle = style.font_color?style.font_color:"#000000";
		if(style.orientation != "vertical"){
			ctx.textAlign = "left";//;style['text-align']?style['text-align']:"center";
			if(!x){
				x = 0;
				//Calculating the width of the text to be drawn
				var w = ctx.measureText(text).width;
				//Calculating the point 'x', based on the alignment
				switch(style['text-align']){
					case 'left':
						x = style['margin-left']?style['margin-left']:10;
						break;
					case 'right':
						x = mWidth - (w + style['margin-right']?style['margin-right']:0 );
						break;
							
					case 'center':
					default:
						x = (mWidth/2) - w/2;
						break;
				}
			}
			if(y == undefined){
				if(this.y!=undefined){
					y = this.y;
				} else{
					y = style['margin-top']?style['margin-top']:10;
				}
			}
			x+=this.x;
		}else{
			if(x == undefined){
				if(this.x!=undefined){
					x = this.x;
				}else{
					x = style['margin-left']?style['margin-left']:10;
				}
			}
			if(y == undefined){
				y = 0;
				//Calculating the width of the text to be drawn
				var w = ctx.measureText(text).width;
				//Calculating the point 'y', based on the alignment
				switch(style['text-align']){
					case 'bottom':
						ctx.textAlign = "left";
						y = style['margin-bottom']?style['margin-bottom']:10;
						break;
					case 'top':
						ctx.textAlign = "right";
						y = mHeight - (w + style['margin-top']?style['margin-top']:10 );
						break;
					case 'middle':
					default:
						ctx.textAlign = "center";
						y = (mHeight/2);// - (w/2);
						break;
				}
			}
			y+=this.y;
			ctx.translate(x, y);
			ctx.rotate(-Math.PI/2);
			x = 0; y = 0;
		}
		
		//ctx.scale(0.9, 0.8);
		ctx.fillText(text, x, y);
		ctx.restore();
	}, showTooltip: function(ctx, x, y, tip, parent){
		ctx.font = '10px Arial';
		ctx.fillStyle="#000";
		ctx.strokeStyle="#000";
		var rX = x+15, rY = y+15, lineHeight = 15;
		var texts = tip.split("\n");
		
		var rHeight = (texts.length*lineHeight)+5;
		var rWidth = 0;
		for(var i=0;i<texts.length;i++){
			var w = ctx.measureText(texts[i]).width+10;
			if(w>rWidth){rWidth=w;}
		}
		if(parent && parent.height){
			if(rY+rHeight > parent.height){rY = parent.height - rHeight;}
		}
		if(parent && parent.width){
			if(rX+rWidth > parent.width){rX = parent.width - rWidth - 5;}
		}
		this._roundedRect(ctx, rX+0.5, rY+0.5, rWidth, rHeight, 5, "#000", "rgba(204, 204, 204, 0.75)");
		rY+=15;
		for(var i=0;i<texts.length;i++){
			ctx.fillText(texts[i], rX+5, rY+(lineHeight*i));
		}
	}, select: function(v){this.selected = v;},
	_drawStar: function(ctx,r){
		ctx.save();
		ctx.lineWidth=1;
		ctx.beginPath();
		var angle = (Math.PI*2) / 10;
		var degrees = -(Math.PI/2);
		for (var i=0; i< 11; i++){
			var rad = (i % 2 == 0) ? r : r/2;
			var x = rad * Math.cos(degrees);
			var y = rad * Math.sin(degrees);
			if(i == 0){
				ctx.moveTo(x, y);
			} else {
				ctx.lineTo(x, y);
			}
			ctx.stroke();
			degrees += angle;
		}
		ctx.closePath();
		ctx.restore();
	}
	
});

function paint(config){
	config._instance.paint(config);
}

// Pie Chart
var PieChart = Drawable.extend({
	build: function(){
		var elements = this.data.elements;
		if(elements[0].animate ==undefined ){
			elements[0].animate = [{speed: 1}];
		}else if(elements[0].animate[0].speed==undefined){
			elements[0].animate[0].speed = 1;
		}
		var values = elements[0].values;
		if(!values || !values.length || values.length<=0){
			return;
		}
		
		var cx = this.x + (this.width/2);
		var cy = this.y + (this.height/2);
		
		var radius = 0;
		if( this.height< this.width){
			radius = this.height/2;
		}else{
			radius = this.width/2;
		}
		radius = radius - radius*0.1;//10% for margin
		
		this.cx = cx ;
		this.cy = cy;
		this.radius = radius;
		
		//Calculating total
		var total = 0;
		for(var i=0;i<values.length;i++){
			if(!isNaN(values[i])){
				total+=values[i];
			}else{
				total+=values[i].value;
			}
		}
		this.total = total;
		var colors = {};
		var prevAngle = 0; var currAngle = 0;
		
		//Collecting colors
		if(elements[0].colours == undefined) {elements[0].colours=[];}
		for(var i=0;i<values.length;i++){
			if(elements[0].colours[i]){
				colors[elements[0].colours[i]]={};
			}
		}
			
		for(var i=0;i<values.length;i++){
			if(elements[0].colours[i] == undefined){
				var c;
				while(c==null || colors[c]!=null){
					c = ("rgb("+(Math.round(Math.random()*255))+","+(Math.round(Math.random()*255))+","+(Math.round(Math.random()*255))+")").toRGB();
				}
				elements[0].colours[i]=c;
				colors[elements[0].colours[i]]={};
			}
			
			var value = 0;
			if(!isNaN(values[i])){
				value = values[i];
			}else{
				value = values[i].value;
			}
			
			currAngle = prevAngle + (Math.PI*2)/(total/[value]);
			var ps = new PieSlice(this, {
									angle:currAngle, pAngle: prevAngle, 
									value: value, tip:this.getTip(value), color: elements[0].colours[i], 
									alpha: elements[0].alpha,
									pieWidth: (radius*2),
									pieHeight: (radius*2)*.8,
								});
			this.addItem(ps);
			prevAngle = currAngle;
		}
	}, getTip: function(value){
		var tip = this.data.elements[0].tip;
		tip = tip.replace('#value#', value);
		tip = tip.replace('#total#', this.total);
		tip = tip.replace('#percent#', ((value/this.total)*100).toFixed(2) + "%");
		return tip;
	}, mouseevent: function(type, x, y, e, ctx){
		var foundItem = null;
		//var debugArray = new Array();
		
		// Distance between (cx,cy) and (x,y). General formula to find radius when cx, cy, x, y are known.
		// r^2 = (x - cx)^2 + (y - cy)^2
		// r = sqrt{ (x - cx)^2 + (y - cy)^2 }
		var nRadius = Math.sqrt(( Math.abs(x - this.cx)*Math.abs(x - this.cx) ) + ( Math.abs(y - this.cy)*Math.abs(y - this.cy) ));
		if(nRadius <= this.radius){//When (x,y) is within the circle
			var nAngle = Math.atan2(y - this.cy, x - this.cx);
			if(nAngle<0){nAngle=Math.PI+Math.abs(nAngle+Math.PI);}
			for(var i=0; i<this.noOfItems(); i++){
				var item = this.getItem(i);
				item.select(false);
				if(!foundItem && nAngle>item.pAngle && nAngle<item.angle){
					item.select(true);
					foundItem = item;
					continue;
				}
			}
		}
		this.paint({context: ctx});
		if(foundItem){
			foundItem.mouseevent(type, x, y, e, ctx);
		}
		ctx.restore();
	}, paint: function(config){
		var ctx = config.context;
		var elements = this.data.elements;
		/*if(this.paintConfig == undefined){
			this.paintConfig = ctx;
		}*/
		if(this.x != undefined && this.y != undefined && this.width != undefined && this.height!= undefined ){
			ctx.canvas._clearBg(ctx, this.x, this.y, this.width, this.height);
		}
		if(this.animation_completed == true){
			config.animateData = {percent: 1};
		}else{
			if(config.animateData == undefined){
				config.animateData = {percent: 1};
				
				if(elements[0].animate && elements[0].animate[0].speed){
					config.animateData.speed=elements[0].animate[0].speed;
					config.animateData.percent = (this.total/config.animateData.speed)/this.total;
				}
			}else{
				config.animateData.percent += 0.1; 
		}
		}
		for(var i=0;i<this.items.length;i++){
			ctx.save();
			this.items[i].paint(config);
			ctx.restore();
		}
		if(config.animateData.percent<1){
			config._instance = this;
			setTimeout(function(){paint(config);}, 10000/config.animateData.speed);
		}else{
			this.animation_completed = true;
		}
	}, animate: function(){
		this.paint(this.paintConfig);
	}
});

var PieSlice = Drawable.extend({
	init:function(parent, config){
		this._super();
		//this.parent = parent;
		this.angle = config.angle, this.pAngle = config.pAngle;
		this.value = config.value; this.tip = config.tip;
		this.color = config.color; this.alpha = config.alpha;
		this.config = config;
		return this;
	},paint: function(config){
		var ctx = config.context;
		var animateData = config.animateData;
		var cx = this.parent.cx, cy = this.parent.cy, radius = this.parent.radius; 
		
		ctx.strokeStyle = this.color;
		var alpha = this.alpha;
		if(this.selected==true && alpha){
			alpha += alpha*0.4;
		}
		ctx.fillStyle = alpha?this.color.toRGB(alpha):this.color;
		
		var angle = this.angle*animateData.percent;
		if(angle>this.angle){
			angle = this.angle;
		}
		var pAngle = this.pAngle*animateData.percent;
		if(pAngle>this.pAngle){pAngle=this.pAngle;}

		ctx.beginPath();
		if(this.parent.data["3d"]==true){
			ctx.moveTo(cx,cy);
			var sp = [0, 0];
			for(var t = pAngle; t <=angle; t+=0.01){
			   var X = cx+(this.config.pieWidth/2)*Math.cos(t);
			   var Y = cy+(this.config.pieHeight/2)*Math.sin(t);
			   ctx.lineTo(X, Y);
			   if(t == pAngle){
				   sp[0] = X; sp[1] = Y;
			   }
			}
			ctx.lineTo(cx,cy);
			if(pAngle<Math.PI){
				ctx.stroke();
				 ctx.moveTo(sp[0], sp[1]);
				for(var t = pAngle; t <=angle && t<=Math.PI; t+=0.01){
				   var X = cx + ((this.config.pieWidth/2)*Math.cos(t));
				   var Y = cy +20+ (((this.config.pieHeight/2))*Math.sin(t));
				   ctx.lineTo(X, Y);
				}
				var ang = angle<=Math.PI?angle:Math.PI;
				var X = cx+(this.config.pieWidth/2)*Math.cos(ang);
				var Y = cy+(this.config.pieHeight/2)*Math.sin(ang);
				ctx.lineTo(X, Y);
			}
		}else{
			ctx.arc(cx, cy, radius, pAngle, angle, false);
			ctx.lineTo(cx, cy);
			
			var paX = cx + (radius*Math.cos(pAngle));
			var paY = cy + (radius*Math.sin(pAngle));
			var caX = cx + (radius*Math.cos(angle));
			var caY = cy + (radius*Math.sin(angle));
			ctx.lineTo(paX,paY);
		}		
		ctx.fill();
		ctx.stroke();
	}, mouseevent: function(type, x, y, e, ctx){
		this.showTooltip(ctx, x, y, this.tip, this.parent);
	}
});

//Legends
var BaseLegend = Drawable.extend({
	paint: function(config){
		if(this.data.text==null){
			return;
		}
		this._drawText(config.context, this.data, this.width, this.height);
	}
});

var XLegend = BaseLegend.extend({
	build: function(){
		if(!this.data.style){
			this.data.style = {};
		}
		this.data.style.orientation="horizontal";
	}
});

var YLegend = BaseLegend.extend({
	build: function(){
		if(!this.data.style){
			this.data.style = {};
		}
		this.data.style.orientation="vertical";
	}
});

//Axises
var XAxis = Drawable.extend({
	init: function(x, y, width, height, data, config){
		var prop = { stroke: 2, 'tick-height': 3, colour: '#784016', offset: true,
			'grid-colour': '#F5E1AA', 'grid-visible': true, '3d': 0, steps: 1, min: 0, max: null };
		this.merge(data, prop);
		this._super(x, y, width, height, prop, config);
	}, getGroupWidth:function(){
		var pw = (this.width*0.95)/((this.data.max)/this.data.steps);
		//pw*=0.95;
		return pw;
	}, build: function(){
		if(this.data.labels == undefined) this.data.labels = [];
		
		for(var i=this.data.min;i<this.data.max;i++){
			if(i>this.data.labels.length || this.data.labels[i] == undefined){
				this.data.labels[i] = {text: ""+(i+1)};
			}else if (typeClass(this.data.labels[i])=="String"){
				this.data.labels[i] = {text: this.data.labels[i]};
			}
		}
		
	}, paint: function(config){
		var ctx = config.context;
		
		//Drawing line
		ctx.beginPath();
		ctx.strokeStyle = this.data.colour;
		ctx.moveTo(this.x, this.y);
		ctx.lineTo(this.x+this.width, this.y);
		ctx.stroke();
		
		var pw = this.getGroupWidth();
		this.element_width=pw;
		//Draw points, lables & grid
		for(var i=this.data.min;i<this.data.max;i++){
			var x = this.x +(pw*(i+1))-pw/2;
			if(Math.round(x)>=x){
				x=Math.round(x)-0.5;
			}else{
				x=Math.round(x)+0.5;
			}
			//Points
			ctx.strokeStyle = this.data.colour;
			ctx.lineWidth=2;
			ctx.beginPath();
			ctx.moveTo(x, this.y);
			ctx.lineTo(x, this.y+3);
			ctx.stroke();
			//Grid
			if(this.data['grid-visible']==true){
				ctx.lineWidth=1;
				ctx.beginPath();
				ctx.strokeStyle = this.data['grid-colour'];
				ctx.moveTo(x, this.config.chartY);
				ctx.lineTo(x, this.y);
				ctx.stroke();
			}
			ctx.font = "10px 'arial'";
			ctx.textAlign = "center";
			var text = this.data.labels[i].text;
			var w = ctx.measureText(text).width;
			this._drawText(ctx, {text: text, style:{font_color: this.data.labels[i].colour}}, 
					pw, 20, (x-this.x)-w/2, this.y+10);
		}
		
		if(this.parent.data["3d"]==true){
			ctx.beginPath();
			ctx.moveTo(this.x, this.y);
			ctx.lineTo(this.x+20, this.y-20);
			ctx.strokeStyle = this.data.colour;
			ctx.stroke();
			ctx.closePath();
		}
	}
});

var YAxis = Drawable.extend({
	init: function(x, y, width, height, data, config){
		var prop = { stroke: 2, 'tick-height': 3, colour: '#784016', offset: true,
			'grid-colour': '#F5E1AA', 'grid-visible': true, '3d': 0, steps: 1, min: 0, max: null };
		this.merge(data, prop);
		
		var w = 0;
		var ctx = config.parent.config.parent.context.get2dContext();
		ctx.font = "10px 'arial'";
		ctx.textAlign = "left";
		for(var i=data.steps, j=1;i<=data.max;i+=data.steps,j++){
			var text = (i);
			var nw = ctx.measureText(text).width;
			nw+=10;
			if(nw>w){w = nw;}
		}
		if(width<w){width=w;}
		this._super(x, y, width, height, prop, config);
	}, getGroupHeight:function(){
		var pw = this.height/(this.data.max/this.data.steps);
		pw*=0.95;
		return pw;
	}, paint: function(config){
		var ctx = config.context;
		var x = this.x+this.width;
		//Drawing the axis line
		ctx.beginPath();
		ctx.strokeStyle = this.data.colour;
		ctx.moveTo(x, this.y);
		ctx.lineTo(x, this.y+this.height);
		ctx.stroke();
		
		var pw = this.getGroupHeight();
		this.element_height=pw;
		//Draw points, labels & grid
		for(var i=this.data.steps, j=1;i<=this.data.max;i+=this.data.steps,j++){
			var y = this.y+(this.height - (pw*j));
			if(Math.round(y)>y){
				y=Math.round(y)-0.5;
			}else{
				y=Math.round(y)+0.5;
			}
			// Points
			ctx.strokeStyle = this.data.colour;
			ctx.lineWidth=2;
			ctx.beginPath();
			ctx.moveTo(x-3, y);
			ctx.lineTo(x, y);
			ctx.stroke();
			//Grid
			if(this.data['grid-visible']==true){
				ctx.lineWidth=1;
				ctx.beginPath();
				ctx.strokeStyle = this.data['grid-colour'];
				ctx.moveTo(x, y);
				ctx.lineTo(x+this.config.chartWidth, y);
				ctx.stroke();
			}
			//Labels
			ctx.font = "10px 'arial'";
			ctx.textAlign = "left";
			var text = (i);
			var w = ctx.measureText(text).width;
			this._drawText(ctx, {text: text}, this.width, 20, 0, y+3);
		}
	}
});
var Legend = Drawable.extend({
	build: function(){
		if(this.data == undefined) {this.data={};}
		if(this.data.type == undefined){ this.data.type='row';}
		if(this.data.position == undefined){ this.data.position='top';}
		switch(this.data.type){
		case 'col':
			this.height = 22;
			this.width = this.config.parent.width;//TODO - review
			break;
		case 'row':
		default:
			this.height = 10+(12*this.config.parent.data.elements.length);//TODO - review
			this.width = 100;
		}
		
		switch(this.data.position){
		case 'bottom':
			this.x = this.config.parent.x;
			this.y = this.config.parent.height;
			break;
		case 'right':
			this.x = this.config.parent.width-this.width;
			this.y = this.config.parent.y;
			break;
		case 'top':
		default:
			this.x = this.config.parent.x;
			this.y = this.config.parent.y;
		}
	}, getProp: function(v){
		if(v==undefined || this.data.position==v){
			return {x: this.x, y: this.y, width: this.width, height: this.height};
		}else{
			return {x: 0, y: 0, width: 0, height: 0};
		}
	}, paint: function(config){
		var ctx = config.context;
		var elements = this.parent.data.elements;
		if(this.data.border==true){
			ctx.beginPath();
			ctx.strokeStyle=(this.data["border-colour"]==undefined?"#000000":this.data["border-colour"]);
			ctx.rect(parseInt(this.x+5)-0.5, parseInt(this.y)-0.5, this.width-10, this.height-5);
			ctx.stroke();
		}
		var x = this.x+8; var y = this.y+8;
		for(var i=0;i<elements.length;i++){
			ctx.beginPath();
			ctx.strokeStyle = elements[i].colour;
			ctx.lineWidth=5;
			ctx.moveTo(x, y);
			ctx.lineTo(x+5, y);
			ctx.stroke();
			this._drawText(ctx, elements[i], 50, 20, x+10-this.x, y+3);
			if(this.data.type=='row'){y+=12;}
			if(this.data.type=='col'){x+=(5+3+70);}//5: color line length,3: margin
		}
	}
});

var BaseChart = Drawable.extend({
	buildChart:function(){
	}, build: function(){
		this.stack_type = false;
		if(this.data.type=="bar_stack"){
			this.stack_type = true;
		}
		if(this.data.x_axis == undefined) {
			this.data.x_axis={min: 0, max:null};
		}else{
			if(this.data.x_axis.min == undefined) this.data.x_axis.min=0;
			if(this.data.x_axis.max == undefined) this.data.x_axis.max=null;
		}
		
		if(this.data.y_axis==undefined){ 
			this.data.y_axis={min: null, max:null};
		}else{
			if(this.data.y_axis.min == undefined) this.data.y_axis.min=null;
			if(this.data.y_axis.max == undefined) this.data.y_axis.max=null;
		}
		var colors = {};
		var elements = this.data.elements;
		//Collecting colors
		for(var i=0;i<elements.length;i++){
			colors[elements[i].colour]={};
		}
		for(var i=0;i<elements.length;i++){
			if(!elements[i].colour){
				var c;
				while(c==null || colors[c]!=null){
					c = ("rgb("+(Math.round(Math.random()*255))+","+(Math.round(Math.random()*255))+","+(Math.round(Math.random()*255))+")").toRGB();
				}
				elements[i].colour=c;
				colors[elements[i].colour]={};
			}
			//Finding X and Y Axis Max/Min
			var values = elements[i].values;
			if(this.stack_type==false){
				for(var j=0;j<values.length;j++){
					var v = isNaN(values[j])?values[j].value:values[j];
					if(v==null){continue;}
					if(isNaN(v)){ v = v.value;}
					//Min Check
					if(this.data.y_axis.min==null || v<this.data.y_axis.min) this.data.y_axis.min=v;
					//Max Check
					if(this.data.y_axis.max==null || v>this.data.y_axis.max) this.data.y_axis.max=v;
				}
			}
			if(this.data.x_axis.max==null ||this.data.x_axis.max<values.length){ //TODO
				this.data.x_axis.max = values.length;
			}
		}
		//Finding Y Axis Max/Min - For Group on Index
		if(this.stack_type==true){
			for(var i=0;i<this.data.x_axis.max;i++){
				var sum = 0;
				for(var j=0;j<elements.length;j++){
					if(elements[j].values.length>i){
						sum+=(isNaN(elements[j].values[i])?elements[j].values[i].value:elements[j].values[i]);
					}
				}
				//Min Check
				if(this.data.y_axis.min==null || sum<this.data.y_axis.min) 
					this.data.y_axis.min=sum;
				//Max Check
				if(this.data.y_axis.max==null || sum>this.data.y_axis.max) 
					this.data.y_axis.max=sum;
			}
		}
		var config = this.config;
		//Legend
		this.legend = new Legend(null, null, null, null, this.data.legend, {parent: this});
		//Added to chart at last (after the chart is draws)
		//X-Legend
		if(this.data.x_legend!=undefined){
			this.xLegend = new XLegend(this.x+config.y_axis_space+config.y_legend_height, 
				this.y+this.height-this.legend.getProp('bottom').height,
				this.width - (config.y_axis_space+config.y_legend_height), 
				config.x_legend_height, this.data.x_legend);
		}else{
			this.xLegend = new XLegend(this.x+config.y_axis_space, this.y+this.height, 0, 0, {});
		}
		this.addItem(this.xLegend);
		//Y-Legend
		if(this.data.y_legend!=undefined){
			this.yLegend = new YLegend(this.x+7+this.legend.getProp('left').width, this.y,
				config.y_legend_height, 
				this.height - (config.margin_bottom + config.margin_top+config.x_axis_space+config.x_legend_height), 
				this.data.y_legend);
		}else{
			this.yLegend = new YLegend(this.x+7,this.y, 0, 0, {});
		}
		this.addItem(this.yLegend);
	
		this.chartWidth = this.width-
								(this.legend.getProp('left').width+this.legend.getProp('right').width
											+config.y_axis_space+config.y_legend_height);
		this.chartHeight = this.height
				-(config.x_axis_space+this.xLegend.height+this.legend.getProp('bottom').height+this.legend.getProp('top').height);
		
		this.chartX = this.x+config.y_axis_space+config.y_legend_height+this.legend.getProp('left').width; 
		this.chartY = this.y+this.legend.getProp('top').height;
		
		//Y-Axis
		this.yAxis = new YAxis(this.chartX-config.y_axis_space,  this.chartY, config.y_axis_space, this.chartHeight, 
				this.data.y_axis, { chartWidth: this.chartWidth, parent: this });
		this.addItem(this.yAxis);
		
		//X-Axis
		this.xAxis = new XAxis(this.yAxis.x+this.yAxis.width,
				this.y+this.height-(this.xLegend.height + config.x_axis_space+this.legend.getProp('bottom').height),
				this.chartWidth, 
				config.x_axis_space, 
				this.data.x_axis, 
				{
					chartHeight: this.chartHeight,
					chartY: this.chartY
				}
			);
		this.addItem(this.xAxis);
		
		this.buildChart();
		
		this.addItem(this.legend);
	}, mouseevent: function(type, x, y, e, ctx){
		if(x>=this.chartX && x<=this.chartX+this.chartWidth 
				&& y>=this.chartY && y<=this.chartY+this.chartHeight){
			this.mouseeventChart(type, x, y, e, ctx);
		}
	}, paint: function(config){
		var ctx = config.context;
		if(this.x != undefined && this.y != undefined && this.width != undefined && this.height!= undefined ){
			//ctx.clearRect(this.x, this.y, this.width, this.height);
			ctx.canvas._clearBg(ctx, this.x, this.y, this.width, this.height);
		}
		for(var i=0;i<this.items.length;i++){
			ctx.save();
			this.items[i].paint(config);
			ctx.restore();
		}
		this.paintChart(config);
	}
});

var Bar = Drawable.extend({
	paint: function(config){
		var ctx = config.context;
		ctx.beginPath();
		var prop = this.parent.parent.getProperties(this.data.index);
		var color = prop.colour;
		ctx.strokeStyle = color;
		var fillColor = this.selected?color.toRGB(0.6):color.toRGB(0.8);
		ctx.fillStyle = fillColor;
		var is3D = this.parent.parent.data["3d"];
		var topMost = true;
		if(this.config!=undefined && this.config.index+1 < this.parent.data.values.length){
			topMost = false;
		}
		
		switch(this.parent.parent.data["bar-style"]){
		case 'round':
		case 'round_glass':
			var rht = parseInt(this.width/2)+0.5;
			if(topMost==false){
				rht=0;
			}
			var nx = parseInt(this.x)-0.5;
			var ny = this.y+rht;
			if(topMost==true){
				ctx.arc(nx+rht, ny, rht, Math.PI, Math.PI*2);
			}
			ctx.rect(nx, ny, this.width, this.height-rht);
			ctx.fill();
			if(this.parent.parent.data["bar-style"]=='round_glass'){
				ctx.beginPath();
				var nw = this.width*0.55;
				var lingrad = ctx.createLinearGradient(nx+2,0, nx+3+nw,0);  
				lingrad.addColorStop(0, "rgba(255,255,255,0.8)");
				lingrad.addColorStop(1,  fillColor.toRGB("-0.3"));  
				ctx.fillStyle = lingrad;
				ctx.arc((nx+2)+(nw/2), ny, nw/2, Math.PI, Math.PI*2);
				if(this.config==undefined || this.config.index==0){
					ctx.rect(nx+2, ny, nw, (this.height-rht)-1);
				}else{
					ctx.rect(nx+2, ny, nw, (this.height-rht));
				}
				ctx.fill();
				ctx.closePath();
			}
			break;
		case 'cylinder':
			var lingrad = ctx.createLinearGradient(this.x,0,this.x+this.width,0);  
			lingrad.addColorStop(0, fillColor.toDark("+0"));
			lingrad.addColorStop(1,  fillColor);
			var rh=3; 
			
			//Drawing the middle and botton
			ctx.fillStyle = lingrad;
			ctx.moveTo(this.x, this.y);
			if(topMost==false){
				ctx.lineTo(this.x, this.y+this.height-rh);
				ctx.bezierCurveTo(this.x, this.y+this.height, this.x+this.width, this.y+this.height, this.x+this.width, this.y+this.height-rh);
			}else{
				ctx.lineTo(this.x, this.y+this.height);
				ctx.bezierCurveTo(this.x, this.y+this.height+rh, this.x+this.width, this.y+this.height+rh, this.x+this.width, this.y+this.height);
			}
			ctx.lineTo(this.x+this.width, this.y);
			if(is3D == true){
				ctx.bezierCurveTo(this.x+this.width, this.y+rh, this.x, this.y+rh, this.x, this.y);
				ctx.fill();
				
				//Drawing the top ellipse
				if(topMost==true){
					ctx.beginPath();
					ctx.moveTo(this.x, this.y);
					lingrad = ctx.createLinearGradient(this.x,0,this.x+this.width,0);  
					lingrad.addColorStop(0, fillColor);
					lingrad.addColorStop(1, fillColor.toDark("+0"));
					ctx.fillStyle = lingrad;
					ctx.bezierCurveTo(this.x, this.y-rh, this.x+this.width, this.y-rh, this.x+this.width, this.y);
					ctx.bezierCurveTo(this.x+this.width, this.y+rh, this.x, this.y+rh, this.x, this.y);
				}
			}else{
				if(topMost==false){
					//ctx.lineTo(this.x+this.width, this.y-rh);
					ctx.bezierCurveTo(this.x+this.width, this.y+rh, this.x, this.y+rh, this.x, this.y);
				}else{
					ctx.bezierCurveTo(this.x+this.width, this.y-rh, this.x, this.y-rh, this.x, this.y);
				}
			}
			ctx.fill();
			break;
		default:
			if(is3D == true){
				if(this.height>0){
					var sw = this.width*0.25, rh = this.height*0.05;
					rh=7;
					if(topMost==false){
						rh=0;
					}
					var mw = this.width-sw, mh = this.height-rh;
					//Main Bar
					ctx.fillStyle = fillColor.toRGB("-0.15");
					ctx.rect(this.x, this.y+rh, mw, mh);
					ctx.fill();
					//3D - left side
					ctx.beginPath();
					ctx.fillStyle = fillColor;
					ctx.rect(this.x+mw, this.y+rh, sw, mh);
					ctx.moveTo(this.x+mw, this.y+rh);
					ctx.lineTo(this.x+mw+sw, this.y);
					ctx.lineTo(this.x+mw+sw, this.y+rh);
					ctx.fill();
					if(rh>0){
						//3D top
						ctx.beginPath();
						ctx.fillStyle = fillColor.toRGB("-0.3");
						ctx.moveTo(this.x, this.y+rh);
						ctx.lineTo(this.x+sw, this.y);
						ctx.lineTo(this.x+mw+sw, this.y);
						ctx.lineTo(this.x+mw, this.y+rh);
						ctx.fill();
					}
				}
			}else{
				ctx.rect(this.x, this.y, this.width, this.height);
				ctx.fill();
			}
		}
	}, mouseevent: function(type, x, y, e, ctx){
		this.showTooltip(ctx, x, y, ""+this.data.value, this.parent.parent);
	}
});

var BarGroup =  Drawable.extend({
	init: function(x, y, width, height, data, config){
		this._super(x, y, width, height, data, config);
		this.data.values = [];
	}, addBar: function(i, v){
		this.data.values.push({index:i, value:v});
	}, paint: function(config){
		if(this.startX == undefined){
			var barWidth = parseInt(this.width/this.parent.bar_counts);
			if(barWidth>25){
				barWidth = 25;
			}
			this.barWidth = barWidth;
			var x = this.x;
			var yStep = this.parent.yAxis.data.steps;
			//var yMax = this.parent.yAxis.data.max;
			var pHeight = this.parent.yAxis.getGroupHeight();
		
			if(this.parent.stack_type==false){
				if(this.data.values.length*barWidth<this.width){
					x+=( ( this.width-(this.data.values.length*barWidth))/2 );
				}
				this.startX = x;
				for(var i=0;i<this.data.values.length;i++){
					var v = this.data.values[i];
					var ht = (v.value/yStep)*pHeight;
					this.addItem(new Bar(x+(barWidth*i), this.y+(this.height-ht), barWidth, ht, v));
				}
			}else{
				x += ((this.width-barWidth)/2);
				this.startX = x;
				var usedY = 0;
				for(var i=0;i<this.data.values.length;i++){
					var v = this.data.values[i];
					var ht = (v.value/yStep)*pHeight;
					var y = this.y - usedY + (this.height-ht);
					usedY += ht;
					this.addItem(new Bar(x, y, barWidth, ht, v, {index: i}));
				}
			}
		}
		for(var i=0;i<this.noOfItems();i++){
			config.context.save();
			this.getItem(i).paint({context: config.context, index: i, total_index: this.noOfItems()});
			config.context.restore();
		}
	}, valueCount: function(){
		return this.data.values.length;
	}, mouseevent: function(type, x, y, e, ctx){
		var foundItem;
		for(var i=0; i<this.noOfItems(); i++){
			var item = this.getItem(i);
			item.select(false);
			if(foundItem==undefined){
				if(x>=item.x && x<=item.x+item.width && y>=item.y && y<=item.y+item.height){
					foundItem = item;
					item.select(true);
				}
			}
		}
		this.parent.paint({context: ctx});
		if(foundItem){
			foundItem.mouseevent(type, x, y, e, ctx);
		}
	}, select: function(v){
		this.selected = v;
		for(var i=0; i<this.noOfItems(); i++){
			this.getItem(i).select(false);
		}
	}
});

//Bar Chart
var BarChart =  BaseChart.extend({
	buildChart: function(){
		var bGroups = {};
		var elements = this.data.elements;
		for(var i=0;i<elements.length;i++){
			var values = elements[i].values;
			for(var j=0;j<values.length;j++){
				var bg = bGroups[j];
				if(!bg){
					bg = new BarGroup(this.yAxis.x+this.yAxis.width+1+(this.xAxis.getGroupWidth()*j), 
							this.y+this.legend.getProp('top').height, 
							this.xAxis.getGroupWidth(), 
							this.height-(this.xAxis.height+this.xLegend.height+this.legend.getProp('top').height
									+this.legend.getProp('bottom').height+1),
							{}, {});
					bGroups[j] = bg;
					this.addItem(bg);
				}
				bg.addBar(i, isNaN(values[j])?values[j].value:values[j]);
			}
		}
		this.bar_counts = 0;
		for(var bg in bGroups){
			if(bGroups[bg] instanceof BarGroup){
				if(bGroups[bg].valueCount()>this.bar_counts){
					this.bar_counts = bGroups[bg].valueCount();
				}
			}
		}
	}, paintChart: function(config){
	}, getProperties: function(i){
		return this.data.elements[i];
	}, mouseeventChart: function(type, x, y, e, ctx){
		var foundItem;
		for(var i=0; i<this.noOfItems(); i++){
			var item = this.getItem(i);
			item.select(false);
			if(foundItem==undefined){
				if(x>=item.x && x<=item.x+item.width && y>=item.y && y<=item.y+item.height){
					foundItem = item;
					foundItem.select(true);
					foundItem.mouseevent(type, x, y, e, ctx);
				}
			}
		}
		// this.paint({context: ctx});
		if(foundItem){
			foundItem.mouseevent(type, x, y, e, ctx);
		}
	}
});

var LinePoint = Drawable.extend({
	_internalPaint: function(ctx, mevent){
		ctx.save();
		ctx.beginPath();
		ctx.strokeStyle = this.parent.data.colour;
		var size = this.parent.data["dot-style"]["dot-size"];
		switch(this.parent.data["dot-style"].type){
		case "star":
			if(mevent){ size++;}
			//Clearing the BG and drawing the start.
			ctx.save();
			ctx.beginPath();
			ctx.arc(this.x+(this.width/2), this.y, size/2, 0, Math.PI*2);
			ctx.clip();
			ctx.canvas._clearBg(ctx, this.parent.x, this.parent.y, this.parent.width, this.parent.height);
			ctx.restore();
			
			ctx.beginPath();
			ctx.translate(this.x+(this.width/2), this.y);
			this._drawStar(ctx, size);
			break;
		case "dot":
		case "solid-dot":
		default:
			if(this.parent.data["dot-style"].type=="solid-dot" && mevent){size++;}
			if(mevent || this.parent.data["dot-style"].type=="solid-dot"){
				ctx.fillStyle = this.parent.data.colour;
				ctx.arc(this.x+(this.width/2), this.y, size, 0, Math.PI*2);
				ctx.fill();
			}
		}
		ctx.stroke();
		ctx.closePath();
		ctx.restore();
	}, paint: function(config){
		if(this.selected == true) return;
		var ctx = config.context;
		this._internalPaint(ctx, false);
	}, mouseevent: function(type, x, y, e, ctx){
		/*ctx.beginPath();
		ctx.fillStyle = this.parent.data.colour;
		ctx.arc(this.x+(this.width/2), this.y, this.parent.data["dot-style"]["dot-size"], 0, Math.PI*2);
		ctx.fill();
		*/
		this._internalPaint(ctx, true);
		this.showTooltip(ctx, this.x+(this.width/2), y, ""+this.data.value, this.parent.parent);
	}
});

var LineGroup = Drawable.extend({
	build: function(){
		if(this.data["dot-style"]==undefined){
			this.data["dot-style"] = {};
		}
		if(this.data["dot-style"].type == undefined) this.data["dot-style"].type= "dot";
		if(this.data["dot-style"]["dot-size"] == undefined) this.data["dot-style"]["dot-size"]= 3;
		if(this.data["dot-style"].colour == undefined) this.data["dot-style"].colour= this.data.colour;
		
		var gw = this.config.parent.xAxis.getGroupWidth();
		var yStep = this.config.parent.yAxis.data.steps;
		var pHeight = this.config.parent.yAxis.getGroupHeight();
		for(var i=0;i<this.data.values.length;i++){
			if(this.data.values[i]==null){this.data.values[i]=0;}
			var value = this.data.values[i];
			var ht = (value/yStep)*pHeight;
			var y = this.y+this.height-ht;
			this.addItem(new LinePoint(this.x+(gw*i), y, gw, 10, {value: value}));
		}
	}, paint: function(config){
		var gw = this.config.parent.xAxis.getGroupWidth();
		var ctx = config.context;
		ctx.beginPath();
		ctx.strokeStyle=this.data.colour;
		ctx.lineWidth=1;
		for(var i=0;i<this.noOfItems();i++){
			var item = this.getItem(i);
			if(i==0){
				ctx.moveTo(parseInt(item.x+(gw/2))-0.5,item.y);
			}else{
				ctx.lineTo(parseInt(item.x+(gw/2))-0.5,item.y);
			}
		}
		ctx.stroke();
		for(var i=0;i<this.noOfItems();i++){
			ctx.save();
			this.getItem(i).paint(config);
			ctx.restore();
		}
	}, getNearPoint: function(x, y){
		for(var i=0;i<this.noOfItems();i++){
			var item = this.getItem(i);
			if(x>=item.x && x<=item.x+item.width){
				return item;
			}
		}
	}
});

var LineChart =  BaseChart.extend({
	buildChart: function(){
		var elements = this.data.elements;
		for(var i=0;i<elements.length;i++){
			var bg = new LineGroup(this.chartX, this.chartY, this.chartWidth, this.chartHeight, elements[i], {parent: this});
			this.addItem(bg);
		}
	}, paintChart: function(config){
	},  mouseeventChart: function(type, x, y, e, ctx){
		var fountLinePoint;
		for(var i=0;i<this.noOfItems();i++){
			var item = this.getItem(i);
			if(item instanceof LineGroup){
				var lPoint = item.getNearPoint(x, y);
				if(fountLinePoint==undefined){
					fountLinePoint = lPoint;
				}else if(Math.abs(y - lPoint.y)<= Math.abs(y - fountLinePoint.y)){
					fountLinePoint = lPoint;
				}
			}
		}
		this.paint({context: ctx});
		if(fountLinePoint){
			ctx.save();
			fountLinePoint.mouseevent(type, x, y, e, ctx);
			ctx.restore();
		}
	}
});